package it.unibo.imola.parser.visitor.entity;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StatementSequence extends Instruction{

	private Logger logger = LoggerFactory.getLogger(getClass());
	protected Environment localEnvironment;
	protected Object[] actualParameters;
	protected ArrayList<Statement> statements;
	protected DefinitionInstruction definition;
	
	public StatementSequence(DefinitionInstruction definition) {
		this.definition = definition;
		statements = new ArrayList<Statement>(0);		
	}
	
	@Override
	public boolean check(Environment env) throws Exception {
		super.check(env);
		boolean ret = true;
		// qui gli sto passando l'env GLOBALE
		
		localEnvironment = new Environment();
		// popolo l'env con valori fittizi per fare i controlli
		for(Entry<String,Class<?>> e : definition.getFormalParameters().entrySet()){
			if(e.getValue() == Integer.class){
				localEnvironment.getVariables().put(e.getKey(), new Variable(e.getKey(), new Integer(0)));
			}
			else if(e.getValue() == Float.class){
				localEnvironment.getVariables().put(e.getKey(), new Variable(e.getKey(), new Float(0)));				
			}
			else if(e.getValue() == String.class){
				localEnvironment.getVariables().put(e.getKey(), new Variable(e.getKey(), new String()));				
			}
			else if(e.getValue() == Image.class){
				localEnvironment.getVariables().put(e.getKey(), new Variable(e.getKey(), new Image()));				
			}
			else throw new Exception("unknown e.getValue()");
		}
		
		// qui controllo se le dichiarazioni di variabili sono compatibili con l'environment locale
		// per le call invece faccio riferimento al corrente environment globale, perchè vado a cercare se
		// ci sono le call che ho dichiarato
		for(Statement s : statements){
			if(s instanceof DeclarationStatement){
				if(!s.check(localEnvironment)){
					ret = false;
					if(logger.isDebugEnabled())
						logger.debug("!s.check(localEnvironment)");
				}
			}
			else if (s instanceof CallStatement){
				if(!s.check(env)){
					ret = false;
					if(logger.isDebugEnabled())
						logger.debug("!s.check(env)");
				}
			}
		}
		return ret;
	}
	
	@Override
	public void exec(Environment env) throws Exception {
		super.exec(env);
		if(actualParameters == null)
			throw new Exception("actualParameters == null");
		
		localEnvironment = new Environment();
		// popolo l'env con valori i veri	
		
		Iterator<String> iterator = definition.getFormalParameters().keySet().iterator();
		String varName = null;
		
		for(int i = 0; i < definition.getFormalParameters().size(); i++){			
			if(iterator.hasNext()){
				varName = iterator.next();
				localEnvironment.getVariables().put(varName,new Variable(varName,actualParameters[i]));
			}			
		}
		
		for(Statement s : statements){
			s.exec(localEnvironment);
		}		
	}

	/**
	 * @return the statements
	 */
	public ArrayList<Statement> getStatements() {
		return statements;
	}

	public void setActualParameters(Object[] actualParameters) {
		if(actualParameters == null)
			throw new IllegalArgumentException("actualParameters == null");
		this.actualParameters = actualParameters;
	}

	public DefinitionInstruction getDefinition() {
		// TODO Auto-generated method stub
		return definition;
	}
	
	
	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this);
	}
	
}
